/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.sentry.samples.console;

import io.sentry.Breadcrumb;
import io.sentry.EventProcessor;
import io.sentry.ISpan;
import io.sentry.ITransaction;
import io.sentry.Sentry;
import io.sentry.SentryEvent;
import io.sentry.SentryLevel;
import io.sentry.SpanStatus;
import io.sentry.protocol.Message;
import io.sentry.protocol.User;

import java.util.Collections;

/**
 * Main
 *
 * @since 2021-06-15
 */
public class Main {
    private Main() {
    }

    /**
     * main
     *
     * @param args for main
     * @throws InterruptedException
     */
    public static void main(String[] args) throws InterruptedException {
        Sentry.init(
            options -> {
                // NOTE: Replace the test DSN below with YOUR OWN DSN to see the events from this app in
                // your Sentry project/dashboard
                options.setDsn(
                    "https://502f25099c204a2fbf4cb16edc5975d1@o447951.ingest.sentry.io/5428563");

                // All events get assigned to the release. See more at
                // https://docs.sentry.io/workflow/releases/
                options.setRelease("io.sentry.samples.console@3.0.0+1");

                // Modifications to event before it goes out. Could replace the event altogether
                options.setBeforeSend(
                    (event, hint) -> {
                        // Drop an event altogether:
                        if (event.getTag("SomeTag") != null) {
                            return null;
                        }
                        return event;
                    });

                // Allows inspecting and modifying, returning a new or simply rejecting (returning null)
                options.setBeforeBreadcrumb(
                    (breadcrumb, hint) -> {
                        // Don't add breadcrumbs with message containing:
                        if (breadcrumb.getMessage() != null
                            && breadcrumb.getMessage().contains("bad breadcrumb")) {
                            return null;
                        }
                        return breadcrumb;
                    });

                options.setShutdownTimeout(5000);
                options.setDebug(true);
                options.setDiagnosticLevel(
                    SentryLevel
                        .ERROR);
                options.addInAppExclude("org.jboss");
                options.addInAppInclude("io.sentry.samples");
                options.setTracesSampleRate(1.0);
                options.setTracesSampler(
                    context -> {
                        if (!context.getTransactionContext().getName().startsWith("/products")) {
                            return 0.1;
                        } else {
                            return 0.5;
                        }
                    });
            });

        Sentry.addBreadcrumb(
            "A 'bad breadcrumb' that will be rejected because of 'BeforeBreadcrumb callback above.'");
        Sentry.configureScope(
            scope -> {
                scope.addEventProcessor(new SomeEventProcessor());

                scope.setExtra("SomeExtraInfo", "Some value for extra info");
            });
        Sentry.withScope(
            scope -> {
                scope.setLevel(SentryLevel.FATAL);
                scope.setTransaction("main");
                Sentry.captureMessage("Fatal message!");
            });
        Sentry.captureMessage("Some warning!", SentryLevel.WARNING);
        Exception exception = new RuntimeException("Some error!");
        Sentry.captureException(exception);
        SentryEvent evt = new SentryEvent();
        Message msg = new Message();
        msg.setMessage("Detailed event");
        evt.setMessage(msg);
        evt.addBreadcrumb("Breadcrumb directly to the event");
        User user = new User();
        user.setUsername("some@user");
        evt.setUser(user);
        evt.setFingerprints(Collections.singletonList("NewClientDebug"));
        evt.setLevel(SentryLevel.DEBUG);
        Sentry.captureEvent(evt);

        int count = 10;
        for (int i = 0; i < count; i++) {
            String messageContent = "%d of %d items we'll wait to flush to Sentry!";
            Message message = new Message();
            message.setMessage(messageContent);
            message.setFormatted(String.format(messageContent, i, count));
            SentryEvent event = new SentryEvent();
            event.setMessage(message);
            Sentry.captureEvent(event, SentryLevel.DEBUG);
        }
        ITransaction transaction = Sentry.startTransaction("transaction name", "op");
        ISpan outerSpan = transaction.startChild("child");
        Thread.sleep(100);
        ISpan innerSpan = outerSpan.startChild("jdbc", "select * from product where id = :id");
        innerSpan.setStatus(SpanStatus.OK);
        Thread.sleep(300);
        innerSpan.finish();
        Sentry.captureMessage("this message is connected to the outerSpan");
        outerSpan.finish();
        transaction.finish();
    }

    private static class SomeEventProcessor implements EventProcessor {
        @Override
        public SentryEvent process(SentryEvent event, Object hint) {
            // Here you can modify the event as you need
            if (event.getLevel() != null && event.getLevel().ordinal() > SentryLevel.INFO.ordinal()) {
                event.addBreadcrumb(new Breadcrumb("Processed by " + SomeEventProcessor.class));
            }

            return event;
        }
    }
}
